<template>
	<div class="default-main">

		<cus-form-title icon="local-cus-ruleEngine" label="产线规划">
			<template #after>
				<div style="margin-left: 20px">
					<el-button size="small" type="primary" @click="calculate">
						<template #icon>
							<icon name="el-icon-Search" size="small"></icon>
						</template>
						计算产线
					</el-button>
					<el-button icon="el-icon-Refresh" size="small" type="primary" @click="resetLine">
						重置
					</el-button>
				</div>
			</template>
		</cus-form-title>
		<el-form ref="formRef" :model="params" :rules="rules" class="cus-form" label-width="auto">
			<el-row :gutter="20" justify="start">
				<el-col :span="8">
					<el-form-item label="产物" prop="selectedItem">
						<el-select v-model="params.selectedItem" clearable filterable placeholder="模糊查询"
						           value-key="id">
							<el-option v-for="item in itemOptionList" :key="item.id" :label="item.itemName!" :value="item">
								<div style="display: flex;justify-content: space-between">
									<div>{{ item.itemName }}</div>
									<div v-if="item.image">
										<el-image :src="getImage(item.image)" fit="contain" style="width: 30px; height: 30px"></el-image>
									</div>
								</div>
							</el-option>
						</el-select>
					</el-form-item>
				</el-col>
				<el-col :span="8">
					<el-form-item label="产出速度（/min）" prop="quantityPerMinute">
						<el-input-number v-model="params.quantityPerMinute" :min="1" :step="1" class="w100" controls-position="right"/>
					</el-form-item>
				</el-col>
			</el-row>
			<el-row :gutter="20" justify="start">
				<el-col :span="8">
					<el-form-item label="默认采矿机" prop="defaultMiner">
						<business-code-select v-model="params.defaultMiner" code-type="defaultMiner" placeholder="请选择"/>
					</el-form-item>
				</el-col>
				<el-col :span="8">
					<el-form-item label="自动计算下级产线" prop="defaultExpandAll">
						<el-tooltip :hide-after="0" content="如果遇到无限加载，请关闭此项" placement="bottom-start">
							<el-switch v-model="params.defaultExpandAll"></el-switch>
						</el-tooltip>
					</el-form-item>
				</el-col>
			</el-row>
		</el-form>

		<cus-form-title icon="local-cus-ruleEngine" label="建筑取整优化" style="margin-top: 20px">
			<template #after>
				<div style="margin-left: 20px">
					<el-button v-if="needOptimization" size="small" type="primary" @click="optimize">
						<template #icon>
							<icon name="local-cus-calculate"></icon>
						</template>
						应用优化
					</el-button>
				</div>
			</template>
		</cus-form-title>
		<el-form ref="optimizeFormRef" :model="optimizeParams" class="cus-form" label-width="auto">
			<el-row :gutter="20" justify="space-between">
				<el-col :span="8">
					<el-form-item label="资源采集建筑">
						<el-switch v-model="optimizeParams.considerMiner" @change="judgeOptimization"></el-switch>
					</el-form-item>
				</el-col>
				<el-col :span="16">
					<el-form-item>
						<template #label><span v-if="optimizationTip">优化措施</span></template>
						<el-text :type="needOptimization ? 'warning' : 'success'">{{ optimizationTip }}</el-text>
					</el-form-item>
				</el-col>
			</el-row>
		</el-form>

		<div v-if="showLine">
			<cus-table-title label="产线">
				<template #after>
					<el-tooltip :disabled="!isVisitor()" :hide-after="0" :show-after="500" content="游客模式下，产线收藏功能不可用，请注册账号后使用~" effect="dark"
					            placement="top">
						<el-button v-auth="'g-user-production:saveUserProduction'" :disabled="isVisitor()" size="small" style="margin-left: 20px" type="primary"
						           @click="favor">
							<template #icon>
								<icon name="el-icon-Star"></icon>
							</template>
							收藏
						</el-button>
					</el-tooltip>
				</template>
			</cus-table-title>
			<el-row :gutter="20" justify="space-around">
				<el-col :span="14" :xs="24">
					<!-- 配方树 -->
					<el-tree
							ref="treeRef"
							:default-expand-all="params.defaultExpandAll"
							:expand-on-click-node="false"
							:load="loadNode"
							:props="treeProps"
							class="cus-tree"
							lazy
							@node-collapse="nodeCollapse"
					>
						<template v-slot="{node, data}">
				      <span class="custom-tree-node">
					      <span>
						      <el-link :underline="false" type="primary" @click="showItemDetail(data.itemId)">{{
								      data.itemName
							      }}</el-link>
				          <span>{{ data.quantityPerMinute ? '，' + data.quantityPerMinute + '/min' : '' }}</span>
				          <span v-if="data.byProductList && data.byProductList.length > 0">（副产物：<span
						          v-for="byProduct in data.byProductList"
				          ><el-link :underline="false" type="warning" @click="showItemDetail(byProduct.itemId)">{{
						          byProduct.itemName
					          }}</el-link>{{ '，' + byProduct.quantityPerMinute + '/min' }}<span
						          v-if="data.byProductList.indexOf(byProduct) !== data.byProductList.length - 1"
				          >；</span></span>）</span>
				          <span v-if="data.recipeList.length > 1">
					          <el-link :underline="false" type="success" @click="toChooseRecipe(node, data)">（更换配方）</el-link>
				          </span>
				        </span>
				        <span>
				          <span v-if="data.buildingVo">
					          <el-link :underline="false" type="primary" @click="showBuildingDetail(data.buildingVo.buildingId)">{{
							          data.buildingVo.buildingName
						          }}</el-link>
				            <span>{{ '*' + data.buildingVo.count + '（' + data.buildingVo.countExact + '）' }}</span>
				          </span>
				          <span v-else-if="data.handmadeBuildingVoList && data.handmadeBuildingVoList.length > 0">
				            手搓（<span v-for="building in data.handmadeBuildingVoList">
					            <el-link :underline="false" type="primary"
					                     @click="showBuildingDetail(building.buildingId)">{{ building.buildingName }}</el-link>
				              <span
						              v-if="data.handmadeBuildingVoList.indexOf(building) < data.handmadeBuildingVoList.length - 1">，</span>
				            </span>）
				          </span>
				        </span>
				      </span>
						</template>
					</el-tree>
				</el-col>
				<el-col :span="1"></el-col>
				<el-col :span="9" :xs="24">
					<div class="statistics">
						<cus-form-title :show-divider="false" :show-icon="false" label="数据统计"></cus-form-title>
						<el-collapse v-model="activeNames" class="">
							<el-collapse-item v-if="basicMaterialList.length > 0" name="material" title="原料">
								<!-- 原料 -->
								<el-descriptions :column="1" border>
									<el-descriptions-item v-for="item in basicMaterialList" :key="item.itemId" label-align="center">
										<template #label>
											{{ item.itemName }}
										</template>
										<div class="cus-center">
											{{ item.quantityPerMinute }}/min
											<el-image :src="getImage(item.image!)" fit="contain"
											          style="width: 50px; height: 50px;cursor: pointer;margin-left: 10px"
											          @click="showItemDetail(item.itemId!)"></el-image>
										</div>
									</el-descriptions-item>
								</el-descriptions>
							</el-collapse-item>
							<el-collapse-item v-if="byProductList.length > 0" name="byProduct" title="副产物">
								<!-- 副产物 -->
								<el-descriptions :column="1" border>
									<el-descriptions-item v-for="item in byProductList" :key="item.itemId" label-align="center">
										<template #label>
											{{ item.itemName }}
										</template>
										<div class="cus-center">
											{{ item.quantityPerMinute }}/min
											<el-image :src="getImage(item.image!)" fit="contain"
											          style="width: 50px; height: 50px;cursor: pointer;margin-left: 10px"
											          @click="showItemDetail(item.itemId!)"></el-image>
										</div>
									</el-descriptions-item>
								</el-descriptions>
							</el-collapse-item>
							<el-collapse-item v-if="productionLineBuildingList.length > 0" name="productionLineBuilding" title="建筑">
								<!-- 建筑 -->
								<el-descriptions :column="1" border>
									<el-descriptions-item v-for="building in productionLineBuildingList" :key="building.buildingId"
									                      label-align="center">
										<template #label>
											{{ building.buildingName }}
										</template>
										<div class="cus-center">
											{{ building.count || 1 }}<span
												v-if="building.count && building.count !== building.countExact">（{{ building.countExact }}）</span>&nbsp;
											<el-image :src="getImage(building.image!)" fit="contain"
											          style="width: 50px; height: 50px;cursor: pointer;margin-left: 10px"
											          @click="showBuildingDetail(building.buildingId!)"></el-image>
										</div>
									</el-descriptions-item>
								</el-descriptions>
							</el-collapse-item>
							<el-collapse-item name="power" title="电力">
								<!-- 电力 -->
								<el-descriptions :column="1" border>
									<el-descriptions-item label-align="center">
										<template #label>
											总耗电量
										</template>
										<div class="cus-center">
											{{ totalPower }} MW
										</div>
									</el-descriptions-item>
								</el-descriptions>
							</el-collapse-item>
						</el-collapse>
					</div>
				</el-col>
			</el-row>
		</div>

		<!-- 抽屉（更换配方） -->
		<el-drawer v-model="drawerVisible" append-to-body direction="btt" size="50%" title="更换配方">
			<el-table :data="recipeTableData" border fit highlight-current-row>
				<el-table-column align="center" label="选取" width="60">
					<template v-slot="scope">
						<el-radio-group v-model="selectedRecipeId" @change="selectedRecipeChanged">
							<el-radio :value="scope.row.recipeId">{{ '' }}</el-radio>
						</el-radio-group>
					</template>
				</el-table-column>
				<el-table-column align="center" label="序号" type="index" width="60"></el-table-column>
				<el-table-column align="center" label="配方" min-width="150">
					<template v-slot="scope">
						{{ scope.row.recipeNameDisplayed }}
					</template>
				</el-table-column>
				<el-table-column align="center" label="原料" min-width="150">
					<template v-slot="scope">
						<p v-for="materialVo in scope.row.materialList" class="cus-center">{{
								materialVo.quantityPerProduction + '*'
							}}
							<el-link :underline="false" type="primary" @click="showItemDetail(materialVo.itemId)">
								{{ materialVo.itemName }}
							</el-link>
							{{ '（' + materialVo.quantityPerMinute + '/min）' }}
							<el-image v-if="materialVo.image" :src="getImage(materialVo.image)" fit="contain"
							          style="width: 50px; height: 50px; cursor: pointer" @click="showItemDetail(materialVo.itemId)"
							></el-image>
						</p>
					</template>
				</el-table-column>
				<el-table-column align="center" label="产物" min-width="150">
					<template v-slot="scope">
						<p v-for="productVo in scope.row.productList" class="cus-center">
							{{ productVo.quantityPerProduction + '*' }}
							<el-link :underline="false" type="primary" @click="showItemDetail(productVo.itemId)">{{
									productVo.itemName
								}}
							</el-link>
							{{ '（' + productVo.quantityPerMinute + '/min）' }}
							<el-image v-if="productVo.image" :src="getImage(productVo.image)" fit="contain"
							          style="width: 50px; height: 50px; cursor: pointer" @click="showItemDetail(productVo.itemId)"
							></el-image>
						</p>
					</template>
				</el-table-column>
				<el-table-column align="center" label="生产建筑" min-width="150">
					<template v-slot="scope">
						<p v-if="scope.row.buildingVo" class="cus-center">
							<el-link :underline="false" type="primary" @click="showBuildingDetail(scope.row.buildingVo.buildingId)">{{
									scope.row.buildingVo.buildingName
								}}
							</el-link>
							{{
								scope.row.buildingVo.count ? '*' + scope.row.buildingVo.count + '（' + scope.row.buildingVo.countExact + '）' : ''
							}}
							{{
								(scope.row.buildingVo.needPower === 1 ? '（' + scope.row.buildingVo.power + 'MW' + (scope.row.buildingVo.overclockable === 1 ? '，可超频' : '，不可超频') + '）' : '')
							}}
							<el-image v-if="scope.row.buildingVo.image" :src="getImage(scope.row.buildingVo.image)"
							          fit="contain"
							          style="width: 100px; height: 100px; cursor: pointer"
							          @click="showBuildingDetail(scope.row.buildingVo.buildingId)"
							></el-image>
						</p>
						<div v-if="scope.row.handmadeBuildingVoList && scope.row.handmadeBuildingVoList.length > 0">
							<p v-for="building in scope.row.handmadeBuildingVoList" class="cus-center">
								<el-link :underline="false" type="primary" @click="showBuildingDetail(building.buildingId)">
									{{ building.buildingName }}
								</el-link>
								<el-image v-if="building.image"
								          :src="getImage(building.image)"
								          fit="contain"
								          style="width: 100px; height: 100px; cursor: pointer"
								          @click="showBuildingDetail(building.buildingId)"
								></el-image>
							</p>
						</div>
					</template>
				</el-table-column>
			</el-table>
		</el-drawer>

		<!-- 对话框（物品详情） -->
		<cus-item-dialog v-model:visible="dialogVisible.item" :item-id="itemIdDisplayed"/>

		<!-- 对话框（建筑详情） -->
		<cus-building-dialog v-model:visible="dialogVisible.building" :building-id="buildingIdDisplayed"/>

	</div>
</template>

<script lang="ts" name="ProductionLineOld" setup>

import {getAllItemApi} from '@/api/gameData/recipe.api'
import {nextTick, reactive, ref, watch} from 'vue'
import type {FormInstance, FormRules} from 'element-plus'
import {ElForm, ElLink, ElMessageBox, ElSwitch, ElTree} from 'element-plus'
import {
	containAllMinerRecipe,
	elTreeIterator,
	findInTreeArray,
	focusFormErrorElement,
	getImage,
	greatestCommonDivisor,
	messageError,
	messageWarning,
	MinerNames,
	smallestCommonMultiple,
	treeArrayIterator
} from '@/utils/commonUtil'
import {map, omit} from 'lodash-es'
import CusTableTitle from '@/components/cus-table-title.vue'
import CusFormTitle from '@/components/cus-form-title.vue'
import type Node from 'element-plus/es/components/tree/src/model/node'
import {loadOneStepApi, saveUserProductionApi} from '@/api/gameTool/productionLine.api'
import CusBuildingDialog from '@/components/cus-building-dialog.vue'
import CusItemDialog from '@/components/cus-item-dialog.vue'
import Icon from '@/components/icon.vue'
import BusinessCodeSelect from '@/components/business-code-select.vue'
import {useUserStore} from '@/stores/modules/user.store'
import {routePush} from '@/utils/routeUtil'
import {isVisitor} from '@/utils/authUtil'
import {useRouteParamsStore} from '@/stores/modules/routeParams.store'
import Fraction from 'fraction.js'

const userStore = useUserStore()
const routeParamsStore = useRouteParamsStore()

const formRef = ref<FormInstance>()
const optimizeFormRef = ref<FormInstance>()
const treeRef = ref<InstanceType<typeof ElTree>>()

const treeProps = reactive({
	label: 'name',
	children: 'children',
	isLeaf: 'leaf',
	disabled: 'disabled'
})
const needOptimization = ref(false)
const optimizationTip = ref<string>()
const showLine = ref(false)
const drawerVisible = ref(false)

const params = reactive<{
	selectedItem?: GItem
	quantityPerMinute: number
	defaultExpandAll: boolean
	defaultMiner: number
}>({
	selectedItem: undefined,
	quantityPerMinute: 10,
	defaultExpandAll: true,
	defaultMiner: 0
})
const optimizeParams = reactive<{
	considerMiner: boolean
}>({
	considerMiner: false
})
const optimizedQuantityPerMinute = ref<number>()
const itemOptionList = ref<GItem[]>([])
const recipeTableData = ref<RecipeVo[]>([])
const activeNames = ref(['material', 'byProduct', 'productionLineBuilding', 'power'])
const basicMaterialList = ref<MaterialVo[]>([])
const byProductList = ref<ProductVo[]>([])
const productionLineBuildingList = ref<ProductionLineBuildingVo[]>([])
const totalPower = ref(0)
const operatingNode = ref<Node>()
const selectedRecipeId = ref<number>()
const resolveMap = reactive<Record<number, (data: ProductionTreeDatum[]) => void>>({})
const itemIdDisplayed = ref<number>()
const buildingIdDisplayed = ref<number>()
const dialogVisible = reactive({
	item: false,
	building: false
})
// 记忆配方
// key：代表当前节点路径的字符串，从路径数组转化而来
// value：recipeId
const memorizedRecipeMap = reactive<Map<string, number>>(new Map())
const rules = reactive<FormRules>({
	selectedItem: [
		{required: true, message: '请选择物品', trigger: 'change'}
	],
	quantityPerMinute: [
		{required: true, message: '请输入产出速度', trigger: 'change'}
	],
	defaultExpandAll: [
		{required: true, message: '请选择是否展开子树', trigger: 'change'}
	],
	defaultMiner: [
		{required: true, message: '请选择默认采矿机', trigger: 'change'}
	]
})

watch(() => params.defaultExpandAll, val => {
	if (treeRef.value) {
		treeRef.value.store.defaultExpandAll = val
	}
})

getAllItemApi().then(response => {
	itemOptionList.value = response.data
})

const nodeCollapse = (data: RecipeVo, node: Node, element: HTMLElement) => {
	data.recipeId = undefined
	data.recipeList = []
	data.byProductList = []
	data.buildingVo = undefined
	data.handmadeBuildingVoList = []
	node.loaded = false
	// 删除下级节点的resolve
	if (node.childNodes.length > 0) {
		treeArrayIterator(node.childNodes, node => {
			delete resolveMap[node.id]
		}, 'childNodes')
	}
	// 删除下级节点
	while (node.childNodes.length > 0) {
		treeRef.value!.remove(node.childNodes[0])
	}
	afterTreeLoaded()
}

const loadNode = async (node: Node, resolve: (data: ProductionTreeDatum[]) => void, alternativeRecipeId?: number) => {
	resolveMap[node.id] = resolve
	if (node.level === 0) {
		afterTreeLoaded()
		// 将用户输入的产出速度转化为分数进行精确计算
		const fraction = new Fraction(params.quantityPerMinute)
		const quantityPerMinuteExactFraction = {
			// 分子
			numerator: fraction.n,
			// 分母
			denominator: fraction.d
		}
		return resolve([{
			itemId: params.selectedItem!.id!,
			itemName: params.selectedItem!.itemName!,
			quantityPerMinute: params.quantityPerMinute,
			quantityPerMinuteExactFraction: quantityPerMinuteExactFraction,
			image: params.selectedItem!.image!,
			fluid: params.selectedItem!.fluid!,
			recipeId: undefined,
			recipeList: [],
			buildingVo: undefined,
			handmadeBuildingVoList: [],
			byProductList: []
		}])
	}
	const loadOneStepRequest: LoadOneStepRequest = {
		itemId: node.data.itemId,
		quantityPerMinuteExactFraction: node.data.quantityPerMinuteExactFraction
	}
	const recipeList: LoadOneStepVo[] = (await loadOneStepApi(loadOneStepRequest)).data
	if (recipeList.length === 0) {
		messageWarning(`找不到【${node.data.itemName}】的制作配方，可能需要手动采集`)
		afterTreeLoaded()
		return resolve([])
	} else {
		let recipe
		// 1、更换配方时，不读取记忆，直接用更换的新配方
		if (alternativeRecipeId) {
			for (const recipeListItem of recipeList) {
				if (recipeListItem.recipeId === alternativeRecipeId) {
					recipe = recipeListItem
					break
				}
			}
		}
		// 2、对于采矿的配方，只有选择了“使用当前配置”才会读取记忆，读取不到则使用标准配方
		else if (containAllMinerRecipe(recipeList)) {
			if (params.defaultMiner === 0) {
				let memorizedRecipeId = memorizedRecipeMap.get(findPathToNode(node).toString())
				if (memorizedRecipeId) {
					for (const recipeItem of recipeList) {
						if (recipeItem.recipeId === memorizedRecipeId) {
							recipe = recipeItem
							break
						}
					}
				} else {
					recipe = recipeList[0]
				}
			} else {
				recipe = recipeList[params.defaultMiner - 1]
			}
		}
		// 3、对于普通的配方，有记忆的配方就优先使用记忆的配方
		else {
			let memorizedRecipeId = memorizedRecipeMap.get(findPathToNode(node).toString())
			if (memorizedRecipeId) {
				for (const recipeItem of recipeList) {
					if (recipeItem.recipeId === memorizedRecipeId) {
						recipe = recipeItem
						break
					}
				}
			} else {
				recipe = recipeList[0]
			}
		}
		if (!recipe) {
			messageError('无法匹配配方')
			afterTreeLoaded()
			return resolve([])
		}
		// 构建原料信息，产出物是矿石时原料是空的，产出物不是矿石时有原料
		const materialList: ProductionTreeDatum[] = []
		for (const materialVo of recipe.materialList) {
			materialList.push({
				itemId: materialVo.itemId!,
				itemName: materialVo.itemName!,
				quantityPerMinute: materialVo.quantityPerMinute!,
				quantityPerMinuteExactFraction: materialVo.quantityPerMinuteExactFraction!,
				image: materialVo.image!,
				fluid: materialVo.fluid!,
				recipeId: undefined,
				recipeList: [],
				buildingVo: undefined,
				handmadeBuildingVoList: [],
				byProductList: []
			})
		}
		// 建筑
		// 优先显示自动化产线建筑
		if (recipe.buildingVo) {
			node.data.buildingVo = recipe.buildingVo
		}
		// 没有自动化产线建筑时，显示手搓建筑
		else {
			node.data.handmadeBuildingVoList = recipe.handmadeBuildingVoList
		}
		// 副产物
		node.data.byProductList = recipe.byProductList
		// 配方
		node.data.recipeId = recipe.recipeId
		node.data.recipeList = recipeList
		afterTreeLoaded()
		return resolve(materialList)
	}
}

// tree渲染完成之后的钩子
const afterTreeLoaded = () => {
	nextTick(() => {
		judgeOptimization()
		buildBasicMaterials()
		buildByProductsAndPower()
	})
}

// 判断树中的结点是否全部加载（未使用）
const isAllLoaded = (root?: Node): boolean => {
	if (!root) {
		root = treeRef.value!.root
	}
	if (root !== treeRef.value!.root && root.childNodes.length === 0) {
		return root.loaded
	}
	// 非root
	if (root.childNodes.length > 0) {
		for (const node of root.childNodes) {
			if (!isAllLoaded(node)) {
				return false
			}
		}
		return true
	}
	// root
	return false
}

const getAllBuildingCountExactFractionInTheTree = (node?: Node, arr?: Fraction[]) => {
	if (!treeRef.value || !treeRef.value.root) {
		return []
	}
	if (!node) {
		node = treeRef.value.root
	}
	if (!arr) {
		arr = []
	}
	// 判断是否需要优化资源采集建筑
	if (optimizeParams.considerMiner) {
		if (node.data && node.data.buildingVo && node.data.buildingVo.countExactFraction) {
			arr.push(node.data.buildingVo.countExactFraction)
		}
	} else {
		if (node.data && node.data.buildingVo && node.data.buildingVo.countExactFraction && node.childNodes.length > 0) {
			arr.push(node.data.buildingVo.countExactFraction)
		}
	}
	if (node.childNodes.length > 0) {
		for (const child of node.childNodes) {
			getAllBuildingCountExactFractionInTheTree(child, arr)
		}
	}
	return arr
}

// 判断是否需要优化
const judgeOptimization = () => {
	if (!treeRef.value) {
		return
	}
	const allBuildingCountExactFractionInTheTree = getAllBuildingCountExactFractionInTheTree()
	needOptimization.value = allBuildingCountExactFractionInTheTree.length > 0
	if (needOptimization.value) {
		// 筛选出所有分母
		const denominatorArray = map(allBuildingCountExactFractionInTheTree, 'denominator')
		// 计算分母的最小公倍数
		const smallestCommonMultipleVal = smallestCommonMultiple(denominatorArray).result
		// 如果最小公倍数大于1（不等于1），则每个表示建筑数量的分数都乘以这个公倍数，得到的新的建筑数量就都是整数了，再计算是否可以缩小
		// 如果最小公倍数等于1，说明此时的建筑数量已经都为整数，直接计算是否可以缩小
		let allBuildingCountExactDecimalInTheTreeNew = []
		if (smallestCommonMultipleVal > 1) {
			// 计算乘以最小公倍数后建筑的数量
			for (const buildingCountExactFraction of allBuildingCountExactFractionInTheTree) {
				allBuildingCountExactDecimalInTheTreeNew.push(buildingCountExactFraction.numerator.mul(smallestCommonMultipleVal).div(buildingCountExactFraction.denominator))
			}
		} else {
			allBuildingCountExactDecimalInTheTreeNew = map(allBuildingCountExactFractionInTheTree, 'numerator')
		}
		// 求最大公约数，以便判断是否可以缩小
		const greatestCommonDivisorVal = greatestCommonDivisor(allBuildingCountExactDecimalInTheTreeNew)
		// 获取当前的产出速度
		const quantityPerMinute = treeRef.value!.root.childNodes[0].data.quantityPerMinute
		// 新的产出速度
		optimizedQuantityPerMinute.value = quantityPerMinute.mul(smallestCommonMultipleVal).div(greatestCommonDivisorVal)
		// 显示优化结果
		if (smallestCommonMultipleVal > greatestCommonDivisorVal) {
			optimizationTip.value = '生产规模扩大为原来的' + smallestCommonMultipleVal + (greatestCommonDivisorVal === 1 ? '' : '/' + greatestCommonDivisorVal) + '倍，新产出速度为：' + optimizedQuantityPerMinute.value
		} else if (smallestCommonMultipleVal < greatestCommonDivisorVal) {
			optimizationTip.value = '生产规模缩小为原来的' + smallestCommonMultipleVal + '/' + greatestCommonDivisorVal + '，新产出速度为：' + optimizedQuantityPerMinute.value
		} else {
			needOptimization.value = false
			optimizationTip.value = '无'
		}
	} else {
		optimizationTip.value = '无'
	}
}

const optimize = () => {
	params.quantityPerMinute = optimizedQuantityPerMinute.value!
	calculate()
}

const buildMemorizedRecipeMap = (node?: Node) => {
	if (!node) {
		node = treeRef.value!.root
	}
	// 判断是否有替代配方，有则记忆选择的配方
	if (node.data && node.data.recipeList && node.data.recipeList.length > 1) {
		memorizedRecipeMap.set(findPathToNode(node).toString(), node.data.recipeId)
	}
	if (node.childNodes.length > 0) {
		for (const child of node.childNodes) {
			buildMemorizedRecipeMap(child)
		}
	}
}

const calculate = () => {
	formRef.value!.validate(valid => {
		if (valid) {
			// 清空相关数据
			for (const key in resolveMap) {
				delete resolveMap[key]
			}
			memorizedRecipeMap.clear()
			// 判断是否需要记忆当前选择的配方
			if (treeRef.value && treeRef.value.root.childNodes[0] && treeRef.value.root.childNodes[0].data.itemId === params.selectedItem!.id) {
				buildMemorizedRecipeMap()
			}
			showLine.value = false
			nextTick(() => {
				showLine.value = true
			})
		} else {
			focusFormErrorElement()
		}
	})
}

const resetLine = () => {
	formRef.value!.resetFields()
	memorizedRecipeMap.clear()
	treeRef.value?.remove(treeRef.value.root.childNodes[0])
	needOptimization.value = false
	optimizationTip.value = undefined
	optimizedQuantityPerMinute.value = undefined
	recipeTableData.value = []
	basicMaterialList.value = []
	byProductList.value = []
	productionLineBuildingList.value = []
	totalPower.value = 0
	operatingNode.value = undefined
	selectedRecipeId.value = undefined
	for (const key in resolveMap) {
		delete resolveMap[key]
	}
	showLine.value = false
}

const favor = () => {
	if (!treeRef.value) {
		messageError('请先计算产线')
		return
	}
	let treeData: ProductionTreeDatumWithChildren[] = [treeRef.value.root.childNodes[0].data]
	treeArrayIterator(treeData, (datum: ProductionTreeDatumWithChildren) => {
		const node = findInTreeArray(treeRef.value!.root.childNodes, (node: Node) => {
			return node.id === datum.$treeNodeId
		}, 'childNodes')
		if (!node) {
			throw Error('无法匹配节点')
		}
		datum.children = []
		for (const childNode of node.childNodes) {
			datum.children.push(<ProductionTreeDatumWithChildren>childNode.data)
		}
	})
	// 删除$treeNodeId字段
	treeData = [omit(treeData[0], ['$treeNodeId', 'recipeId', 'recipeList'])]
	treeArrayIterator(treeData, (datum: ProductionTreeDatumWithChildren) => {
		if (datum.children && datum.children.length > 0) {
			const newChildren = []
			for (const child of datum.children) {
				newChildren.push(omit(child, ['$treeNodeId', 'recipeId', 'recipeList']))
			}
			datum.children = newChildren
		}
	})
	// data字段的数据
	const data: ProductionLineData = {
		treeData: treeData,
		statistics: {
			basicMaterialList: basicMaterialList.value,
			byProductList: byProductList.value,
			productionLineBuildingList: productionLineBuildingList.value,
			totalPower: totalPower.value
		}
	}
	ElMessageBox.prompt('产线名称：', '收藏', {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		draggable: true,
		inputValue: `${treeData[0].itemName}（${treeData[0].quantityPerMinute}/min）` + (treeData[0].handmadeBuildingVoList && treeData[0].handmadeBuildingVoList.length > 0 ? '（手搓）' : '')
	}).then(({value}) => {
		const request: SaveUserProductionRequest = {
			type: 1,
			userId: userStore.userId!,
			productionName: value,
			itemId: treeData[0].itemId,
			quantityPerMinute: treeData[0].quantityPerMinute,
			data: JSON.stringify(data)
		}
		doSaveUserProduction(request)
	}).catch(() => {
	})
}

const doSaveUserProduction = (request: SaveUserProductionRequest) => {
	saveUserProductionApi(request).then(response => {
		if (response.data) {
			ElMessageBox.prompt('产线名称已存在，请更换其他名称：', '名称重复', {
				type: 'error',
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				draggable: true,
				inputValue: request.productionName
			}).then(({value}) => {
				request.productionName = value
				doSaveUserProduction(request)
			}).catch(() => {
			})
		} else {
			ElMessageBox.confirm(`产线已收藏，请在【游戏工具 - 我的产线】中查看`, '成功', {
				confirmButtonText: '知道了',
				cancelButtonText: '去查看',
				type: 'success',
			}).then(() => {
			}).catch(() => {
				routeParamsStore.setParams({handleSearch: 1}, 'ProductionLineCollectionOld')
				routePush({name: 'ProductionLineCollectionOld'})
			})
		}
	})
}

const showItemDetail = (itemId: number) => {
	itemIdDisplayed.value = itemId
	dialogVisible.item = true
}

const showBuildingDetail = (buildingId: number) => {
	buildingIdDisplayed.value = buildingId
	dialogVisible.building = true
}

const toChooseRecipe = (node: Node, data: RecipeVo) => {
	operatingNode.value = node
	selectedRecipeId.value = data.recipeId
	recipeTableData.value = data.recipeList
	drawerVisible.value = true
}

const selectedRecipeChanged = () => {
	loadNode(operatingNode.value!, resolveMap[operatingNode.value!.id], selectedRecipeId.value)
	drawerVisible.value = false
	// 如果更换的是采矿机配方，则默认采矿机改为“使用当前配置”
	const selectedRecipe = recipeTableData.value.find(recipe => recipe.recipeId === selectedRecipeId.value)
	if (MinerNames.includes(selectedRecipe?.buildingVo?.buildingName!)) {
		params.defaultMiner = 0
	}
	// 更换配方后删除相关的记忆
	let changingKey = findPathToNode(operatingNode.value!).toString()
	// 删除更换的节点的记忆
	memorizedRecipeMap.delete(changingKey)
	for (const key of memorizedRecipeMap.keys()) {
		if (key.startsWith(changingKey) && key.replace(changingKey, '').startsWith(',')) {
			// 删除更换的节点的下级节点的记忆
			memorizedRecipeMap.delete(key)
		}
	}
}

// 计算原料
const buildBasicMaterials = (root?: Node) => {
	if (!root) {
		root = treeRef.value!.root
		basicMaterialList.value = []
	}
	// 是叶子节点（即产线所需的原料）
	if (root.childNodes.length === 0) {
		let found = false
		for (const item of basicMaterialList.value) {
			if (item.itemId === root.data.itemId) {
				found = true
				item.quantityPerMinute = item.quantityPerMinute!.add(root.data.quantityPerMinute)
				break
			}
		}
		if (!found) {
			basicMaterialList.value.push({
				itemId: root.data.itemId,
				itemName: root.data.itemName,
				quantityPerMinute: root.data.quantityPerMinute,
				image: root.data.image
			})
		}
	}
	// 非叶子节点
	else {
		for (const node of root.childNodes) {
			buildBasicMaterials(node)
		}
	}
}

// 计算副产物和电力
const buildByProductsAndPower = () => {
	totalPower.value = 0
	byProductList.value = []
	productionLineBuildingList.value = []
	const handler = (node: Node) => {
		// 电力
		if (node.data.buildingVo && node.data.buildingVo.needPower === 1) {
			totalPower.value += node.data.buildingVo.power
		}
		// 副产物
		if (node.data.byProductList && node.data.byProductList.length > 0) {
			for (const byProduct of node.data.byProductList) {
				let found = false
				for (const item of byProductList.value) {
					if (item.itemId === byProduct.itemId) {
						found = true
						item.quantityPerMinute = item.quantityPerMinute!.add(byProduct.quantityPerMinute)
						break
					}
				}
				if (!found) {
					byProductList.value.push({
						itemId: byProduct.itemId,
						itemName: byProduct.itemName,
						quantityPerMinute: byProduct.quantityPerMinute,
						image: byProduct.image
					})
				}
			}
		}
		// 自动化产线建筑
		if (node.data.buildingVo) {
			let found = false
			for (const building of productionLineBuildingList.value) {
				if (building.buildingId === node.data.buildingVo!.buildingId) {
					found = true
					building.count += node.data.buildingVo!.count
					building.countExact = building.countExact!.add(node.data.buildingVo!.countExact!)
					break
				}
			}
			if (!found) {
				productionLineBuildingList.value.push({
					buildingId: node.data.buildingVo.buildingId,
					buildingName: node.data.buildingVo.buildingName,
					needPower: node.data.buildingVo.needPower,
					power: node.data.buildingVo.power,
					image: node.data.buildingVo.image,
					overclockable: node.data.buildingVo.overclockable,
					count: node.data.buildingVo.count,
					countExact: node.data.buildingVo.countExact,
					countExactFraction: node.data.buildingVo.countExactFraction
				})
			}
		}
		// 手搓建筑
		if (node.data.handmadeBuildingVoList && node.data.handmadeBuildingVoList.length > 0) {
			for (const handmadeBuildingVo of node.data.handmadeBuildingVoList) {
				let found = false
				for (const building of productionLineBuildingList.value) {
					if (building.buildingId === handmadeBuildingVo.buildingId) {
						found = true
						break
					}
				}
				if (!found) {
					productionLineBuildingList.value.push({
						buildingId: handmadeBuildingVo.buildingId,
						buildingName: handmadeBuildingVo.buildingName,
						needPower: handmadeBuildingVo.needPower,
						power: handmadeBuildingVo.power,
						image: handmadeBuildingVo.image,
						overclockable: handmadeBuildingVo.overclockable
					})
				}
			}
		}
	}
	elTreeIterator(treeRef.value!, handler)
}

// 返回表示某个节点的访问路径的数组
const findPathToNode = (target: Node, node?: Node, arr?: number[]) => {
	if (!treeRef.value) {
		throw Error('树还未初始化')
	}
	if (!target) {
		throw Error('目标节点为空')
	}
	if (!node) {
		node = treeRef.value.root
	}
	if (!arr) {
		arr = []
	}
	if (node === target) {
		const index = getIndex(node)
		if (index === false) {
			throw Error('无法匹配节点')
		}
		arr.unshift(index)
		return node === treeRef.value.root ? arr : true
	}
	// 继续找下级节点
	else {
		let result = false
		for (const child of node.childNodes) {
			if (findPathToNode(target, child, arr)) {
				result = true
			}
		}
		if (result) {
			const index = getIndex(node)
			if (index === false) {
				throw Error('无法匹配节点')
			}
			arr.unshift(index)
		}
		return result && node === treeRef.value.root ? arr : result
	}
}

// 获取在同级节点中的位置
const getIndex = (node: Node) => {
	if (!node.parent) {
		return 0
	} else {
		for (let i = 0; i < node.parent.childNodes.length; i++) {
			if (node.parent.childNodes[i] === node) {
				return i
			}
		}
	}
	return false
}

</script>

<style lang="scss" scoped>
.custom-tree-node {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: var(--el-font-size-base);
	padding-right: 8px;
}

.statistics {
	border-radius: var(--el-border-radius-base);
	box-shadow: var(--cus-box-shadow);
	padding: 10px;
}
</style>
